using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using DrawTools.Editor.CanvasFigures;

namespace DrawTools.Editor
{
  /// <summary>
  ///   List of graphic objects
  /// </summary>
  public sealed class GraphicsList : IEnumerable<CanvasObject>
  {
    private readonly List<CanvasObject> _graphicsList = new List<CanvasObject>();

    /// <summary>
    ///   Count and this [nIndex] allow to read all graphics objects
    ///   from GraphicsList in the loop.
    /// </summary>
    public int Count
    {
      get { return _graphicsList.Count; }
    }

    public CanvasObject this[int index]
    {
      get
      {
        if (index < 0 || index >= _graphicsList.Count)
          return null;

        return _graphicsList[index];
      }
    }

    /// <summary>
    ///   SelectedCount and GetSelectedObject allow to read
    ///   selected objects in the loop
    /// </summary>
    public IEnumerable<CanvasObject> SelectedObjects
    {
      get { return _graphicsList.Where(o => o.IsSelected); }
    }

    public void DrawFigures(Graphics g)
    {
      // Enumerate list in reverse order
      // to get first object on the top
      for (int i = _graphicsList.Count - 1; i >= 0; i--)
      {
        _graphicsList[i].Draw(g);
      }
    }

    public void DrawTrackers(Graphics g)
    {
      // Enumerate list in reverse order
      // to get first object on the top
      for (int i = _graphicsList.Count - 1; i >= 0; i--)
      {
        _graphicsList[i].DrawTracker(g);
      }
    }

    //public void Draw(Graphics g)
    //{
    //  if (_graphicsList.Count == 0)
    //  {
    //    using (var brush = new SolidBrush(Color.FromArgb(120, Color.Black)))
    //    {
    //      g.FillRectangle(brush, g.ClipBounds);
    //    }
    //  }
    //  else
    //  {
    //    // Enumerate list in reverse order
    //    // to get first object on the top
    //    // but crop object should be drawn on the top 
    //    // despite it is always on bottom in GraphicList.
    //    // Because we have to shade objects outside of the crop object.
    //    var drawingList = _graphicsList.Where(i => !(i is CanvasCrop)).Reverse().Union(_graphicsList.Where(i => i is CanvasCrop)).ToList();

    //    foreach (var canvasObject in drawingList)
    //    {
    //      canvasObject.Draw(g);
    //    }

    //    foreach (var canvasObject in drawingList)
    //    {
    //      canvasObject.DrawTracker(g);
    //    }
    //  }
    //}

    /// <summary>
    ///   Clear all objects in the list
    /// </summary>
    /// <returns>
    ///   true if at least one object is deleted
    /// </returns>
    public bool Clear()
    {
      bool result = (_graphicsList.Count > 0);
      _graphicsList.Clear();
      return result;
    }

    public CanvasObject GetObjectAtPoint(Point point, bool includeHandles)
    {
      return GetObjectListAtPoint(point, includeHandles).FirstOrDefault();
    }

    public IEnumerable<CanvasObject> GetObjectListAtPoint(Point point, bool includeHandles)
    {
      foreach (CanvasObject t in _graphicsList)
      {
        int hitResult = t.HitTest(point);

        if (includeHandles ? hitResult >= 0 : hitResult == 0)
          yield return t;
      }
    }

    public void Add(CanvasObject obj)
    {
      // insert to the top of z-order
      _graphicsList.Insert(0, obj);
    }

    public void SelectInRectangle(Rectangle rectangle)
    {
      DeselectAll();

      foreach (CanvasObject o in _graphicsList)
      {
        if (o.IntersectsWith(rectangle))
          o.IsSelected = true;
      }
    }

    public void DeselectAll()
    {
      foreach (CanvasObject o in _graphicsList)
      {
        o.IsSelected = false;
      }
    }

    public void SelectAll()
    {
      foreach (CanvasObject o in _graphicsList)
      {
        o.IsSelected = true;
      }
    }

    /// <summary>
    ///   Delete selected items
    /// </summary>
    /// <returns>
    ///   true if at least one object is deleted
    /// </returns>
    public bool DeleteSelection()
    {
      bool result = false;

      int n = _graphicsList.Count;

      for (int i = n - 1; i >= 0; i--)
      {
        CanvasObject selectedObject = _graphicsList[i];

        if (selectedObject.IsSelected)
        {
          _graphicsList.RemoveAt(i);
          result = true;
        }
      }

      return result;
    }

    /// <summary>
    ///   Move selected items to front (beginning of the list)
    /// </summary>
    public void MoveSelectionToFront()
    {
      var tempList = new List<CanvasObject>(_graphicsList);
      _graphicsList.Clear();

      _graphicsList.AddRange(tempList.Where(o => o.IsSelected));
      _graphicsList.AddRange(tempList.Where(o => !o.IsSelected));
    }

    /// <summary>
    ///   Move selected items to back (end of the list)
    /// </summary>
    public void MoveSelectionToBack()
    {
      var tempList = new List<CanvasObject>(_graphicsList);
      _graphicsList.Clear();

      _graphicsList.AddRange(tempList.Where(o => !o.IsSelected));
      _graphicsList.AddRange(tempList.Where(o => o.IsSelected));
    }

    #region IEnumerable<CanvasObject> Members

    public IEnumerator<CanvasObject> GetEnumerator()
    {
      return _graphicsList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return GetEnumerator();
    }

    #endregion
  }
}